package com.example.netty.java;

import java.util.LinkedList;
import java.util.List;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.util.concurrent.EventExecutorGroup;

/**
 * 描述:
 * 创建者：pjh
 * 创建日期：2020/10/10
 * UpdateUser:更新者
 * 更新时间：2020/10/10
 */
public abstract class ChannelPipelineFactory<C extends Channel> extends ChannelInitializer<C> {
    private volatile boolean _debug = false;
    EventExecutorGroup _group;

    public ChannelPipelineFactory(EventExecutorGroup executor) {
        _group = executor;
    }

    public ChannelPipelineFactory() {
    }

    public EventExecutorGroup getGroup() {
        return _group;
    }

    public ChannelPipelineFactory<C> debug() {
        _debug = true;
        return this;
    }

    public static HandlerList handlerList(ChannelHandler... handlers) {
        HandlerList result = new HandlerList();
        int i = 0;
        for (ChannelHandler handler : handlers) {
            result.addLast(handler.getClass().getSimpleName() + "_" + i, handler);
        }
        return result;
    }

    @SuppressWarnings("serial")
    public static class HandlerList extends LinkedList<HandlerEntry> {
        Channel _channel;

        public void addLast(String name, ChannelHandler handler) {
            super.addLast(new HandlerEntry(name, handler));
        }

        public void addLast(String name, ChannelHandler handler, EventExecutorGroup group) {
            super.addLast(new HandlerEntry(name, handler, group));
        }

        public void mixin(ChannelHandlerContext ctx) {
            ChannelPipeline pipeline = ctx.pipeline();
            for (HandlerEntry entry : this) {
                pipeline.addLast(entry.getKey(), entry.getValue());
            }
            _channel = ctx.channel();

        }

        public boolean hasChannel() {
            return _channel != null && _channel.isActive();
        }

        public void close() {
            if (_channel != null)
                try {
                    _channel.close().sync();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }

    }

    public static class HandlerEntry {
        ChannelHandler _value;
        String _key;
        EventExecutorGroup _group;

        public HandlerEntry(String name, ChannelHandler handler) {
            this(name, handler, null);
        }

        public HandlerEntry(String name, ChannelHandler handler, EventExecutorGroup group) {
            _value = handler;
            _key = name;
            _group = group;
        }

        public String getKey() {
            return _key;
        }

        public ChannelHandler getValue() {
            return _value;
        }

        public EventExecutorGroup getGroup() {
            return _group;
        }

    }

    @Override
    protected void initChannel(C ch) throws Exception {
        if (_debug)
            ch.pipeline().addFirst("xlogger", new OutLogger("first"));

        List<HandlerEntry> list = getPipeline();
        for (HandlerEntry entry : list) {
            if (entry.getGroup() == null)
                ch.pipeline().addLast(entry.getKey(), entry.getValue());
            else
                ch.pipeline().addLast(entry.getGroup(), entry.getKey(), entry.getValue());
        }

        // System.out.println("added "+list.size()+" handlers to pipeline "+ch);
    }

    public abstract HandlerList getPipeline() throws Exception;

}
